# -*- coding: utf-8 -*-
from ladon.ladonizer import ladonize
from ladon.types.ladontype import LadonType
from comm.att.struct.sync_action import *
import string
import re
import json
from mysite.personnel.models.model_issuecard import IssueCard,issuedate_valid
#from mysite.pos.models.model_loseunitecard import LoseUniteCard
from mysite.iclock.models.model_device import Device,DEVICE_POS_SERVER
from mysite.personnel.models.model_emp import Employee,format_pin
from base.sync_api import SYNC_MODEL
from django.conf import settings
from mysite.utils import get_option
class IssuecardService(object):
    u'''【卡操作】包括发卡、退卡、挂失、解挂操作'''
    
    
    u"""【退卡】退卡前请确认该卡的消费记录都已采集完成！退卡过程中系统将会清除卡内数据！"""
    @ladonize(str,str,str,rtype=str)
    def issuecardRetreat(self,pin,cardno,card_cost):
        '''
                退卡
        @param pin:参数一，人员编号 
        @param cardno:参数二，卡号
        @param card_cost:参数三，卡成本
        @rtype: 返回信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -146   卡号不存在
            -147   人员编号与对应卡号不一致
            -148   该卡号有余额，请先退款
        '''
        from mysite.personnel.models.model_issuecard import PRIVAGE_CARD
        from mysite.pos.models.model_cardmanage import CardManage
        from mysite.pos.models.model_cardserial import CardSerial
        from ooredis import Dict
        from django.core.cache import cache
        from mysite.pos.models import CarCashSZ
        RET_INFO={}
        RET_INFO['option'] = 'issuecardRetreat'
        RET_INFO['ret'] = format_valid(pin,cardno)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_card = IssueCard.objects.get(cardno = cardno)
        except:
            RET_INFO['ret'] = '-146'#无此卡号
            return json.dumps(RET_INFO)
        if temp_card.UserID.PIN != temp_pin:
            RET_INFO['ret'] = '-147'#人员编号与对应卡号不一致
            return json.dumps(RET_INFO)
        if get_option("POS"):
            if temp_card.blance > 0:
                RET_INFO['ret'] = '-148'
                return json.dumps(RET_INFO)
            if temp_card.card_privage <> PRIVAGE_CARD:
                CarCashSZ( user=temp_card.UserID,
                           card=temp_card.cardno,
                           checktime = datetime.datetime.now(),
                           type_id=4,#retire cost type
                           money=card_cost or 0,
                           hide_column=4,
                           blance=temp_card.blance).save()
            else:
                obj_card_manage = CardManage.objects.get(card_no = temp_card.cardno)
                obj_card_manage.delete() 
        if get_option("POS_ID") and temp_card.card_privage <> PRIVAGE_CARD:
            obj = CardSerial.objects.get(cardno=int(temp_card.cardno))
            obj.delete()
        if get_option("POS_ID") and get_option("USE_POS_COMM_MODEL") and temp_card.card_privage <> PRIVAGE_CARD: 
            serial_redis = Dict("pos_id_card_serial:dict_card")
            del serial_redis[int(temp_card.cardno)]
        RET_INFO['id'] = temp_card.id
        temp_card.delete()
        key="IssueCard_%s" %temp_card.cardno
        cache.delete(key)
        RET_INFO['ret'] = '0'
        return json.dumps(RET_INFO) 
       
    u"""【卡解挂】解挂输入人员编号所对应的卡号"""
    @ladonize(str,str,rtype=str)
    def issuecardRevert(self,pin,cardno):
        '''
                解挂
        @param pin:参数一，人员编号 
        @param cardno:参数二，卡号
        @rtype: 返回信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -146   卡号不存在
            -147    人员编号与对应卡号不一致
            -149    该卡号已是有效卡号不可解挂
            -150    该人员编号已有正在使用的卡，不可解挂
            -151    IC管理卡不可解挂
            -152    IC操作卡不可解挂
            -153    已停用卡不可解挂
            -154    过期卡不可解挂
            -155    该人员编号已离职不可解挂
        '''
        from mysite.pos.models.model_loseunitecard import LoseUniteCard
        from base.cached_model import STATUS_LEAVE
        from mysite.personnel.models.model_issuecard import PRIVAGE_CARD,OPERATE_CARD,CARD_VALID,CARD_LOST,CARD_OVERDUE,CARD_STOP,CARD_INVALID
        from mysite.pos.models.model_cardmanage import CardManage
        from mysite.iclock.models.dev_comm_operate import delete_pos_device_info
        from mysite.iclock.models.model_device import Device,DEVICE_POS_SERVER
        RET_INFO={}
        RET_INFO['option'] = 'issuecardRevert'
        RET_INFO['ret'] = format_valid(pin,cardno)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_card = IssueCard.objects.get(cardno = cardno)
        except:
            RET_INFO['ret'] = '-146'
            return json.dumps(RET_INFO)
        if get_option("POS_IC") and temp_card.card_privage ==  PRIVAGE_CARD:#IC管理卡不可解挂
            RET_INFO['ret'] = '-151'
            return json.dumps(RET_INFO)
        if get_option("POS_IC") and temp_card.card_privage ==  OPERATE_CARD:#IC操作卡不可解挂
            RET_INFO['ret'] = '-152'
            return json.dumps(RET_INFO)
        if temp_card.card_privage <> PRIVAGE_CARD and temp_card.UserID.status == STATUS_LEAVE:#该人员编号已离职不可解挂
            RET_INFO['ret'] = '-155'
            return json.dumps(RET_INFO)
        if temp_card.type and not issuedate_valid(temp_card.type_id,temp_card.issuedate):#过期卡不可解挂
            RET_INFO['ret'] = '-154'
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_VALID:#该卡号已是有效卡号不可解挂
            RET_INFO['ret'] = '-149'
            return json.dumps(RET_INFO)
        if temp_card.cardstatus ==  CARD_STOP:#已停用卡不可解挂
            RET_INFO['ret'] = '-153'
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_LOST:#挂失卡
            if temp_card.UserID.PIN != temp_pin:
                RET_INFO['ret'] = '-147'#人员编号与对应卡号不一致
                return json.dumps(RET_INFO)
            
            if temp_card.card_privage <> PRIVAGE_CARD:
                obj = IssueCard.objects.filter(UserID = temp_card.UserID,cardstatus = CARD_VALID)
            else:
                RET_INFO['ret'] = '-150'#该人员编号已有正在使用的卡，不可解挂
                return json.dumps(RET_INFO) 
            
            if get_option("POS_ID"):
                if temp_card.card_privage  == PRIVAGE_CARD:
                    LoseUniteCard(
                             cardno = cardno,
                             type = temp_card.type,
                             cardstatus=CARD_VALID,
                             time = datetime.datetime.now()).save()
                    obj_card_manage = CardManage.objects.get(card_no = temp_card.cardno)
                    obj_card_manage.cardstatus = CARD_VALID
                    obj_card_manage.save()
                else:
                    LoseUniteCard(UserID = temp_card.UserID,
                                 cardno = cardno,
                                 type = temp_card.type,
                                 cardstatus=CARD_VALID,
                                 time = datetime.datetime.now()).save()
            if get_option("POS_IC") :
                LoseUniteCard(UserID = temp_card.UserID,
                        cardno = temp_card.cardno,
                        type = temp_card.type,
                        cardstatus=CARD_VALID,
                        sys_card_no=temp_card.sys_card_no,
                        Password=temp_card.Password,
                        time = datetime.datetime.now()).save()
                dev = Device.objects.filter(device_type = DEVICE_POS_SERVER)
                delete_pos_device_info(dev,[temp_card],"USERINFO")
            temp_card.cardstatus = CARD_VALID#修改为有效卡号
            temp_card.save()
            RET_INFO['ret'] = '0'#IC消费解挂成功
            RET_INFO['id'] = temp_card.id#IC消费解挂成功
            return json.dumps(RET_INFO)
        
    u"""【卡挂失】挂失输入人员编号所对应的卡号"""
    @ladonize(str,str,rtype=str)
    def issuecardLose(self,pin,cardno):
        '''
                挂失
        @param pin:参数一，人员编号 
        @param cardno:参数二，卡号
        @rtype: 返回信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -146    卡号不存在
            -147    人员编号与对应卡号不一致
            -156    IC管理卡不可挂失
            -157    IC操作卡不可挂失
            -158    已挂失卡不可挂失
            -159    已停用卡不可挂失
        '''
        from mysite.pos.models.model_loseunitecard import LoseUniteCard
        from mysite.personnel.models.model_issuecard import PRIVAGE_CARD,OPERATE_CARD,CARD_VALID,CARD_LOST,CARD_OVERDUE,CARD_STOP,CARD_INVALID
        from mysite.pos.models.model_cardmanage import CardManage
        from mysite.iclock.models.dev_comm_operate import update_pos_device_info
        from mysite.iclock.models.model_device import Device,DEVICE_POS_SERVER
        RET_INFO={}
        RET_INFO['option'] = 'issuecardLose'
        RET_INFO['ret'] = format_valid(pin,cardno)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_card = IssueCard.objects.get(cardno = cardno)
        except:
            RET_INFO['ret'] = '-146'#无此卡号
            return json.dumps(RET_INFO)
        if get_option("POS_IC") and temp_card.card_privage == PRIVAGE_CARD:
            RET_INFO['ret'] = '-156'#IC管理卡不可挂失
            return json.dumps(RET_INFO)
        if get_option("POS_IC") and temp_card.card_privage == OPERATE_CARD:
            RET_INFO['ret'] = '-157'#IC操作卡不可挂失
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_LOST:
            RET_INFO['ret'] = '-158'#已挂失卡不可挂失
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_STOP:
            RET_INFO['ret'] = '-159'#已停用卡不可挂失
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_VALID:
            if temp_card.UserID.PIN != temp_pin:
                RET_INFO['ret'] = '-147'#人员编号与对应卡号不一致
                return json.dumps(RET_INFO)
            if get_option("POS_ID"):
                if temp_card.card_privage == PRIVAGE_CARD:
                    LoseUniteCard(
                                 cardno = temp_card.cardno,
                                 type = temp_card.object.type,
                                 cardstatus=CARD_LOST,
                                 time = datetime.datetime.now()).save()
                    obj_card_manage = CardManage.objects.get(card_no = temp_card.cardno)
                    obj_card_manage.cardstatus = CARD_LOST
                    obj_card_manage.save()
                else:
                    LoseUniteCard(UserID = temp_card.UserID,
                                 cardno = cardno,
                                 type = temp_card.type,
                                 cardstatus=CARD_LOST,
                                 time = datetime.datetime.now()).save()
            if get_option("POS_IC") and temp_card.sys_card_no:
                LoseUniteCard(UserID = temp_card.UserID,
                             cardno = temp_card.cardno,
                             type = temp_card.type,
                             cardstatus=CARD_LOST,
                             sys_card_no=temp_card.sys_card_no,
                             Password=temp_card.Password,
                             time = datetime.datetime.now()).save()
                dev = Device.objects.filter(device_type = DEVICE_POS_SERVER)
                update_pos_device_info(dev,[temp_card],"USERINFO")
            temp_card.cardstatus = CARD_LOST#修改为挂失卡号
            temp_card.save()
            RET_INFO['ret'] = '0'#IC挂失成功
            RET_INFO['id'] = temp_card.id#IC挂失成功
            return json.dumps(RET_INFO)
                
                
    u"""【发卡】验证是否有人员编号所对应的卡号"""
    @ladonize(str,str,str,str,str,str,str,rtype=str)
    def issuecardAdd(self,pin,cardno,Password,mng_cost,blance,card_cost,card_privage):
        """
                发卡
        @param pin:参数一，人员编号 (选填)
        @param cardno:参数二，卡号 (必填)
        @param Password:参数三，人员密码(选填)
        @param mng_cost:参数四，管理费 (选填)
        @param blance:参数五，金额 (选填)
        @param card_cost:参数六，卡成本 (选填)
        @param card_privage:参数七，卡 类型,0--普通卡，1--管理卡，2--操作卡(必填)
        @rtype: 返回信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -97    人员编号不存在
            -101    卡号已被使用
            -106    人员密码必须为整数
            -150    该人员已有正在使用的卡
            -160    管理费不能为负数
            -161    金额不能为负数
            -162    卡成本不能为负数
        """
        from mysite.personnel.models.model_issuecard import CARD_OVERDUE,CARD_VALID,POS_CARD,PRIVAGE_CARD,OPERATE_CARD,blance_valid
        import re
        from mysite.pos.models import CarCashSZ
        from mysite.pos.pos_constant import TIMEOUT 
        from base.cached_model import cache
        RET_INFO={}
        RET_INFO['option'] = 'issuecardAdd'
        if card_privage in [PRIVAGE_CARD,OPERATE_CARD]:
            old_emp = None
            RET_INFO['ret'] = format_valid(pin,cardno,check_pin = False)
            if RET_INFO['ret'] != '-1' :
                return json.dumps(RET_INFO)
        else:
            RET_INFO['ret'] = format_valid(pin,cardno)
            if RET_INFO['ret'] != '-1' :
                return json.dumps(RET_INFO)
            temp_pin = format_pin(pin)
            try:
                old_emp = Employee.objects.get(PIN=temp_pin)
            except:
                RET_INFO['ret'] = '-97'#无此人员编号
                return json.dumps(RET_INFO) 
        old_card = IssueCard.objects.filter(cardno = cardno)
        if old_card:
            RET_INFO['ret'] = '-101'#卡已被使用
            return json.dumps(RET_INFO)
        if get_option("POS"):
            obj = IssueCard.objects.filter(UserID = old_emp,cardstatus__in = [CARD_OVERDUE,CARD_VALID],card_privage = POS_CARD)
        else:
            obj = IssueCard.objects.filter(UserID = old_emp,cardstatus__in = [CARD_VALID])
        if obj:
            RET_INFO['ret'] = '-150'
            return json.dumps(RET_INFO)
        
        new_card = IssueCard()
        new_card.cardno = cardno
        is_manager_card = False#是否管理卡
        new_card.UserID = old_emp
        new_card.card_privage = POS_CARD
        if get_option("POS"):
            tmp = re.compile('^[0-9]+$')
            if not tmp.match(Password or '123456'):
                RET_INFO['ret'] = '-106'
                return json.dumps(RET_INFO)
            if int(mng_cost or 0)< 0:
                RET_INFO['ret'] = '-160'
                return json.dumps(RET_INFO)
            if int(blance or 0)< 0:
                RET_INFO['ret'] = '-161'
                return json.dumps(RET_INFO)
            if int(card_cost or 0)< 0:
                RET_INFO['ret'] = '-162'
                return json.dumps(RET_INFO)
            new_card.Password = Password or "123456"
            new_card.mng_cost = mng_cost or 0
            new_card.blance = blance or 0
            new_card.card_cost = card_cost or 0
            if card_privage in [PRIVAGE_CARD,OPERATE_CARD]:#新增管理卡
                new_card.card_privage = card_privage
                is_manager_card = True
            else:
                if get_option("POS_ID"):
                    try:
                        CarCashSZ(user=old_emp,
                               card = cardno,
                               checktime = datetime.datetime.now(),
                               type_id = 7,#cost type
                               money = card_cost or 0,
                               hide_column = 7,blance = blance or 0).save()
                        CarCashSZ(user = old_emp,
                               card = cardno,
                               checktime = datetime.datetime.now(),
                               type_id =1,#cost type
                               money = blance or 0,
                               hide_column = 1,blance = blance or 0).save()
                        CarCashSZ(user = old_emp,
                               card = cardno,
                               checktime = datetime.datetime.now(),
                               type_id =11,#cost type
                               money=mng_cost or 0,
                               hide_column=11,blance=blance or 0).save()
                    except Exception, e:
                        import traceback;traceback.print_exc()
        new_card.cardstatus=CARD_VALID
        super(IssueCard,new_card).save()
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = new_card.id
        return json.dumps(RET_INFO)
        
    u"""【换卡】验证是否有人员编号所对应的卡号"""
    @ladonize(str,str,str,rtype=str)
    def issuecardChange(self,pin,old_cardno,new_cardno):
        """
                换卡
        @param pin:参数一，人员编号 
        @param old_cardno:参数二，旧卡号
        @param new_cardno:参数三，新卡号 
        @rtype: 返回信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -150    该人员已有正在使用的有效卡
            -163    人员编号与对应旧卡号不一致
            -164    旧卡为管理卡，换卡失败
            -165    旧卡号不存在
            -166    该人员已经离职，换卡失败
            -167    旧卡已停用，换卡失败
        """
        from mysite.personnel.models.model_issuecard import CARD_OVERDUE,CARD_VALID,POS_CARD,PRIVAGE_CARD,OPERATE_CARD,blance_valid,CARD_STOP
        import re
        from mysite.pos.models import CarCashSZ
        from base.cached_model import STATUS_LEAVE
        from base.cached_model import cache,cache_key
        from mysite.pos.models import ReplenishCard
        RET_INFO={}
        RET_INFO['option'] = 'issuecardChange'
        RET_INFO['ret'] = format_valid(pin,new_cardno)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_card = IssueCard.objects.get(cardno = old_cardno)
        except:
            RET_INFO['ret'] = '-165'#无此卡号
            return json.dumps(RET_INFO)
        if temp_card.UserID.PIN != temp_pin:
            RET_INFO['ret'] = '-163'
            return json.dumps(RET_INFO)
        if temp_card.card_privage == PRIVAGE_CARD:
            RET_INFO['ret'] = '-164'
            return json.dumps(RET_INFO)
        if temp_card.UserID.status == STATUS_LEAVE:
            RET_INFO['ret'] = '-166'
            return json.dumps(RET_INFO)
        if temp_card.cardstatus == CARD_STOP:
            RET_INFO['ret'] = '-167'
            return json.dumps(RET_INFO)
        obj = IssueCard.objects.filter(UserID = temp_card.UserID,cardstatus__in = [CARD_OVERDUE,CARD_VALID],card_privage = POS_CARD)
        if obj:
            RET_INFO['ret'] = '-150'
            return json.dumps(RET_INFO)
        ReplenishCard(user=temp_card.UserID,
                       oldcardno=old_cardno,
                       newcardno=new_cardno,
                       blance=temp_card.blance).save()
        card_blance = temp_card.blance
        if get_option("POS_ID"):
            temp_card.blance = 0
            temp_card.cardstatus = CARD_STOP
            super(IssueCard, temp_card).save()
            key = cache_key(temp_card,temp_card.pk)
            cache.delete(key)
            CarCashSZ(user=temp_card.UserID,
                 card=temp_card.cardno,
                 checktime = datetime.datetime.now(),
                 type_id=5,#charge type
                 money=card_blance,
                 hide_column=5,blance=temp_card.blance).save()
            new_card = IssueCard(UserID = temp_card.UserID,
                    cardno = new_cardno,
                    cardstatus = CARD_VALID,
                    blance = card_blance,
                    card_cost = temp_card.card_cost,
                    mng_cost = temp_card.mng_cost,
                    type = temp_card.type )
            new_card.save()
            RET_INFO['id'] = new_card.id
        RET_INFO['ret'] = '0'
        return json.dumps(RET_INFO)    
#验证人员编号与卡号的格式正确性 
def format_valid(pin,cardno,check_cardno = True,check_pin = True):
    if check_pin:
        p_text = r'^[0-9]+$'
        if settings.PIN_SUPPORT_LETTERS and get_option("ONLY_ATT"): 
            p_text = r'^[0-9a-zA-Z]+$'
        p =  re.compile(p_text)
        if not p.match(pin):
            if settings.PIN_SUPPORT_LETTERS and get_option("ONLY_ATT"):
                return '-92'
            else: 
                return '-91'   
        if re.compile(r"^0+$").match(pin):
            return '-93'
        if len(pin) > settings.PIN_WIDTH :
            return '-94'
    
    if check_cardno:#卡的验证，卡是必输项 ，供发卡使用
        t_text = r'^[0-9]+$'
        tmp = re.compile(t_text)
        if not tmp.search(cardno):
            return '-95'
        if int(cardno) == 0:
            return '-96'
    if not check_cardno and len(cardno) !=0: #卡的验证，卡是非必输项，供人员使用
        t_text = r'^[0-9]+$'
        tmp = re.compile(t_text)
        if not tmp.search(cardno):
            return '-95'
        if int(cardno) == 0:
            return '-96'
    return '-1'       
